using System.CodeDom;
using CodeDomHelper.Types;
using System;
using System.Diagnostics;

namespace CodeDomHelper.CodeDom
{

    [DebuggerDisplay("{VariableName}", Name = "VariableExp")]
    [Serializable()]
    [System.Diagnostics.DebuggerStepThrough()]
    public partial class VariableExp : CodeVariableReferenceExpression, IType
    {

        #region ctor


        public VariableExp(PropertyExp property)
            : base(property.PropertyName)
        {
            Type = new TypeExp(property.Type);
            this.root = property;
        }

        public VariableExp(ParameterExp parameter)
            : base(parameter.Name)
        {
            Type = new TypeExp(parameter.Type);
            this.root = parameter;
        }

        public VariableExp(FieldExp field)
            : base(field.FieldName)
        {
            Type = new TypeExp(field.Type);
            this.root = field;
        }

        public VariableExp(MethodInvoke method)
            : base(method.MethodRoot.MethodName)
        {

            if (method.Type == null)
                throw new Exception("the method is void. You can't convert the return in Variable.");

            Type = new TypeExp(method.Type);
            this.root = method.MethodRoot.TargetObject;
        }


        public VariableExp(System.String variableName, Type type)
            : base(variableName)
        {
            Type = new TypeExp(type);
        }

        public VariableExp(System.String variableName, string typeName)
            : base(variableName)
        {
            Type = new TypeExp(typeName);
        }

        public VariableExp(System.String variableName, TypeExp type)
            : base(variableName)
        {
            Type = new TypeExp(type);
        }

        public VariableExp(System.String variableName, TypeExpression type)
            : base(variableName)
        {
            Type = new TypeExp(type);
        }

        #endregion



        public TypeExp Type { get; private set; }

        public CodeObjectCreateExpression New(params CodeExpression[] parameters)
        {
            return Type.New(parameters);
        }        

        public CodeDefaultValueExpression DefaultValue()
        {
            return Type.DefaultValue;
        }


        #region Property

        public PropertyExp Property(string propertyName, string typeName)
        {
            return new PropertyExp(this.root ?? this, propertyName, typeName);
        }

        public PropertyExp PropertyExp(string propertyName, TypeExp type)
        {
            return new PropertyExp(this.root ?? this, propertyName, type);
        }

        public PropertyExp Property(string propertyName, Type type)
        {
            return new PropertyExp(this.root ?? this, propertyName, type);
        }

        public PropertyExp Property(string propertyName, TypeExpression type)
        {
            return new PropertyExp(this.root ?? this, propertyName, type);
        }

        #endregion

        #region Field

        public FieldExp Field(string fieldName, string typeName)
        {
            return new FieldExp(this.root ?? this, fieldName, typeName);
        }

        public FieldExp Field(string fieldName, TypeExp type)
        {
            return new FieldExp(this.root ?? this, fieldName, type);
        }

        public FieldExp Field(string fieldName, Type type)
        {
            return new FieldExp(this.root ?? this, fieldName, type);
        }

        public FieldExp Field(string fieldName, TypeExpression type)
        {
            return new FieldExp(this.root ?? this, fieldName, type);
        }

        #endregion

        #region Method

        public MethodExp Method(string methodName)
        {
            return new MethodExp(this, methodName);
        }

        public MethodExp Method(string methodName, TypeExp typeReturn)
        {
            return new MethodExp(this.root ?? this, methodName, typeReturn);
        }

        #endregion


        public CodeBinaryOperatorExpression IsNull { get { return Helper.IsNull(this); } }
        public CodeBinaryOperatorExpression IsNotNull { get { return Helper.IsNotNull(this); } }

        public CodeExpression root { get; set; }


        public static implicit operator VariableExp(FieldExp field)
        {
            return new VariableExp(field);
        }

        public static implicit operator VariableExp(PropertyExp property)
        {
            return new VariableExp(property);
        }

        public static implicit operator VariableExp(MethodInvoke property)
        {
            return new VariableExp(property);
        }


        public CodeCastExpression As(TypeExp type)
        {
            return Helper.Cast(this, type);
        }
    }

}
